{
  "bundles": [
    {
      "@type": "NXBundle",
      "artifactId": "nuxeo-diff-content",
      "artifactVersion": "2021.63.8",
      "bundleGroup": {
        "@type": "NXBundleGroup",
        "bundleIds": [
          "org.nuxeo.diff.content",
          "org.nuxeo.diff.core",
          "org.nuxeo.diff.jsf"
        ],
        "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff",
        "id": "grp:org.nuxeo.diff",
        "name": "org.nuxeo.diff",
        "parentIds": [
          "grp:org.nuxeo.ecm"
        ],
        "readmes": [
          {
            "blobProviderId": "default",
            "content": "# Nuxeo Diff\n\nThis repo hosts the source code of a plugin for Nuxeo Platform that allows to render a diff between two documents or two versions of a document.\nThe comparison takes into account all the properties shared by the documents, which means that if a comparison is done between two documents of a different type, only the schemas in common will be \"diffed\".\nThe comparison also takes into account blob-type properties.\n\n\n## Building and deploying\n\n    mvn clean install\n\n## Deploying\n\nInstall [the Nuxeo Diff Marketplace Package](https://connect.nuxeo.com/nuxeo/site/marketplace/package/nuxeo-diff).\n\n## Configuring\n\n### Diff display\n\nThe `DiffDisplayService` offers several extension points to configure the document diff display.\nMost of the code samples exposed here can be found in the [diff-display-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-display-contrib.xml) and [diff-widgets-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-widgets-contrib.xml) files.\n\n#### Configuring groups of properties to display with the diffDisplay extension point.\n\nA `diffDisplay` contribution represents a number of `diffBlocks` that you want to display when asking for a document comparison.\nIt is bound to a document type.\nA `diffBlock` contribution represents a number of properties (fields) that you want to display (see next section).\n\nWhen asking for the comparison between 2 versions of a document, the `diffDisplay` bound to the document type or a super type is used.\nIf no `diffDisplay` is found for this type or a super type a fall back is done on the default diff display mode: one block per document schema and for each block all the fields of the schema that are different.\n\n*Beware that in this case the order of the schemas and of the fields is undefined.*\n\nWhen asking for the comparison between 2 documents:\n- If they are of the same type: if  a `diffDisplay` is found for this type or a super type then it is used, else a fall back is done on the default diff display mode.\n- If they are of different types: if  a `diffDisplay` is found for a common super type then it is used, else a fall back is done on the default diff display mode.\n\nFor example, this is the `diffDisplay` contribution bound to the _File_ type:\n```xml\n<diffDisplay type=\"File\">\n  <diffBlocks>\n    <diffBlock name=\"heading\" />\n    <diffBlock name=\"dublincore\" />\n    <diffBlock name=\"files\" />\n  </diffDisplay>\n</diffBlocks>\n```\n\n_Note that the order of the diffBlocks is taken into account when rendering the diff display._\n\n#### Configuring a group of properties to display with the diffBlock extension point\n\nA `diffBlock` contribution represents a number of `fields` that you want to display. It is rendered as a foldable box.\nThe `label` attribute of a `diffBlock` contribution is used as the title of the foldable box.\nA `field` is defined by its `schema` and its `name`.\n\nFor example, this is the \"heading\" `diffBlock` contribution:\n```xml\n<diffBlock name=\"heading\" label=\"label.diffBlock.heading\">\n  <fields>\n    <field schema=\"dublincore\" name=\"title\" />\n    <field schema=\"dublincore\" name=\"description\" />\n  </fields>\n</diffBlock>\n```\n_Note that the order of the fields is taken into account when rendering the diff block._\n\nFor complex properties, you can contribute inside the `field` element the property `items` that you want to display:\n```xml\n<field schema=\"complextypes\" name=\"complex\">\n  <items>\n    <item name=\"stringItem\" />\n    <item name=\"thirdItem\" />\n    <item name=\"fourthItem\" />\n  </items>\n</field>\n```\n\n_Note that the order of the items is taken into account when rendering the field._\n\nThis is used for the `files` field of the `files` diff block:\n```xml\n<field schema=\"files\" name=\"files\">\n  <items>\n    <!-- Display the file only, not the filename which is managed\n         by the file widget type -->\n    <item name=\"file\" displayContentDiffLinks=\"true\" />\n  </items>\n</field>\n```\n\nIf no `items` are specified, all the property items are displayed.\n\nFor content properties (that hold a blob) or string ones you can set the `displayContentDiffLinks` attribute to `true` on a `field` or an `item` to display the content diff links.\nThese links will open a fancybox showing the detailed content diff using the usual green and red colors to distinguish the added/removed parts of the content.\nFor now, 2 links are displayed: _Textual diff_ based on a text conversion and _Html diff_ based on an html conversion (keeps the content layout).\n\n#### Configuring property widgets with the widgets extension point\n\n##### Principle\n\nWhen rendering a `diffBlock`, the `DiffDisplayService` builds a layout definition on the fly, including a layout row for each `field` of the `diffBlock`.\nEach row contains a widget definition for the `field`, and the layout template renders 2 instances of this widget definition: one for the left document and one for the right document.\nThe content diff links, if displayed, are also rendered by a widget inside the layout row.\n\nHow is the widget definition built for a given `field`?\nA lookup is done in the `LayoutStore` service to find a specific widget definition named with the xpath of the property.\nIf such a definition is not found, a lookup is done to find a generic widget definition named with the type of the property.\n\nThis allows you to only contribute a specific widget definition if the generic one doesn't match your needs for a given field, typically if you need a custom template, label or custom properties.\n\n##### Example\n\nLets say we have contributed the following `diffBlock`:\n```xml\n<diffBlock name=\"myCustomBlock\" label=\"label.diffBlock.custom\">\n  <fields>\n    <field schema=\"file\" name=\"content\" />\n    <field schema=\"dublincore\" name=\"title\" />\n  </fields>\n</diffBlock>\n```\n\nand the following widgets to the `widgets` extension point of the `org.nuxeo.ecm.platform.forms.layout.LayoutStore` component:\n```xml\n<extension target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\"\n  point=\"widgets\">\n\n  <widget name=\"file:content\" type=\"file\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <labels>\n      <label mode=\"any\">label.summary.download.file</label>\n    </labels>\n    <translated>true</translated>\n    <properties mode=\"any\">\n    </properties>\n  </widget>\n\n  <widget name=\"string\" type=\"template\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <properties mode=\"any\">\n      <property name=\"widgetType\">text</property>\n      <property name=\"template\">\n        /widgets/generic_diff_widget_template.xhtml\n      </property>\n    </properties>\n  </widget>\n\n</extension>\n```\n\nWhen rendering the \"myCustomBlock\" `diffBlock`, the `DiffDisplayService` will:\n\n- Look for a specific widget definition named \"file:content\" in the `LayoutStore`, find it and use it for the \"file:content\" field.\n\n- Look for a specific widget definition named \"dublincore:title\" in the `LayoutStore`, won't find it and therefore will look for a generic widget definition named with the field type, ie. \"string\", find it and use it for the dublincore:title field.\n\nIn this use case, the \"string\" generic widget definition is sufficient to display the \"dublincore:title\" field.\nIt uses a widget of type \"text\" with \"label.dublincore.title\" as a label and \"dublincore:title\" as a field definition.\nWe can easily understand here the interest of generic widgets: once you have the type and xpath of a property, the matching widget definition can be computed on the fly using the property type to guess the widget type (\"string\" => \"text\", \"date\" => \"datetime\", etc.) and the property xpath for the field definition and label.\n\nThe \"file:content\" specific widget definition is contributed here to use a custom label \"label.summary.download.file\" instead of the one that would have been generated for the \"content\" generic widget definition: \"label.file.content\".\n\n_Note that in both cases (generic and specific) you don't need to define the widget field definitions since they are automatically computed from the property xpath, except in particular cases like \"note:note\" where the \"mime-type\" field is needed._\n\n##### List and complex properties\n\nYou might already know that the widgets used to display list and complex properties have subwidgets.\nIn the case of a list property, a subwidget is needed for the list items; in the case of a complex property, a subwidget is needed for each item of the complex property.\nThe lookup done by the `DiffDisplayService_` for the first-level widgets is also done recursively for the subwidgets!\n\n###### List property\n\nFor a list property, lets take the example of \"dublincore:contributors\", which is a string list.\n\n- To display the list, nothing special is needed so the \"scalarList\" generic widget definition can be used.\n\n- To display a list item (a contributor, which is of type \"string\"), the \"string\" generic widget definition doesn't match our needs: it would display the contributor's username whereas we want to display its fullname (firstname lastname).\nSo we need a specific widget definition for the list items subwidget to use a custom template able to display the contributor's fullname.\nThe name of this widget definition must match the xpath of the list item property, ie. \"dublincore:contributors/item\".\n\nTherefore, two widget definitions are involved:\n\n- The \"scalarList\" generic widget definition:\n\n```xml\n<widget name=\"scalarList\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"displayAllItems\">false</property>\n    <property name=\"displayItemIndexes\">true</property>\n    <property name=\"template\">\n      /widgets/list_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"dublincore:contributors/item\" specific widget definition:\n\n```xml\n<widget name=\"dublincore:contributors/item\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.dublincore.contributors.item</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n###### Complex property\n\nFor a complex property, lets take the example of a \"complextypes:complex\" property with two items \"stringItem\" and \"directoryItem\".\n\"stringItem\" is a simple string, but \"directoryItem\" is a string that needs to be bound to the \"myDirectory\" directory.\n\n- To display the complex property, nothing special is needed so the \"complex\" generic widget definition can be used.\n\n- To display the \"directoryItem\" item, the \"string\" generic widget definition doesn't match our needs: it would display the directory entry code stored in the backend whereas we want to display its label.\nSo we need a specific widget definition for the \"directoryItem\" subwidget to use the \"selectOneDirectory\" widget type bound to the \"myDirectory\" directory.\nAs for a list item, the name of this widget definition must match the xpath of the complex property item, ie. \"complextypes:complex/directoryItem\".\n\nTherefore, two widget definitions are involved:\n\n- The \"complex\" generic widget definition:\n\n```xml\n<widget name=\"complex\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"template\">\n      /widgets/complex_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"complextypes:complex/directoryItem\" specific widget definition:\n\n```xml\n<widget name=\"complextypes:complex/directoryItem\" type=\"selectOneDirectory\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.complextypes.complex.directoryItem</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"directoryName\">myDirectory</property>\n    <property name=\"localize\">true</property>\n    <property name=\"ordering\">ordering,label</property>\n  </properties>\n</widget>\n```\n\n###### Useful widget properties\n\nYou can use the following properties on a list widget definition (typically \"scalarList\", \"complexList\" or \"files:files\"):\n\n`<property name=\"displayAllItems\">[true|false]</property>`\nIf set to `true`, all the list items will be displayed, otherwise only the different ones will be.\n\n`<property name=\"displayItemIndexes\">[true|false]</property>`\nIf set to `true`, a subwidget will be added to the widget definition to display the list item indexes.\n\nYou can use the following property on a complex widget definition (typically \"complex\"):\n\n`<property name=\"display\">[inline|*]</property>`\nIf set to `inline` the complex items will be displayed as a table with one line and one column per item, otherwise as a table with one column and one line per item.\n\n##### About the value bound to the diff widgets\n\nIf you take a look at [layout_diff_template.xhtml](nuxeo-diff-jsf/src/main/resources/web/nuxeo.war/layouts/layout_diff_template.xhtml), you will see that the `value` passed to the `<nxl:widget>` tag is `#{value.leftValue}` or `#{value.rightValue}`, `value` being the object passed to the `<nxl:layout>` tag `value` attribute: `diffDisplayBlock`, of type `DiffDisplayBlockImpl`.\nThe `leftValue` and `rightValue` members of `DiffDisplayBlockImpl` are of type `Map<String, Map<String, PropertyDiffDisplay>>`. The first level Map keys are schema names, the second level ones are field keys.\nFinally, the `PropertyDiffDisplay` object has two members: `value` and `styleClass`, `value` holding the value to display and `styleClass` the css style class to apply to the &lt;span&gt; wrapping the value.\n\nFor example if we compare two documents where only the \"dublincore:title\" property is different (\"My first doc\" and \"My second doc\") we could have the following `diffDisplayBlock` object:\n\n```java\ndiffDisplayBlock.getLeftValue() = {dublincore={title={value=\"My first doc\", styleClass=\"redBackgroundColor\"}}}\ndiffDisplayBlock.getRightValue() = {dublincore={title={value=\"My second doc\", styleClass=\"greenBackgroundColor\"}}}\n```\n\nOn the widget side, the field definitions must match the `diffDisplayBlock` object structure, that's why the generated field definitions of the widget used for \"dublincore:title\" would be:\n\n```xml\n<fields>\n  <field>dublincore:title/value</field>\n  <field>dublincore:title/styleClass</field>\n</fields>\n```\n\nThis is important to know when designing a custom template for a diff widget (ie. where field definitions are automatically generated): you can use `#{field_0}` for the value itself and `#{field_1`} for the css style class associated to the value.\nBy default, only the items of a complex property or of a list property where the `displayAllItems` widget property is `true` can have a styleClass equal to `redBackgroundColor` or `greenBackgroundColor` in order to highlight the different items among all.\n\n#### To summarize: what you need to contribute to have a nice diff result for your custom document types\n\n- A `diffDisplay` contribution for each document type.\n\n- The associated `diffBlock` contributions. Don't forget that you can specify the items you want to display for a complex property and the fields/items for which you want to display the content diff links.\n\n- The specific widgets needed when the generic ones don't match your needs. Typically for a date property if you need to change the date format, or for a property bound to a directory to specifiy the directory name. Also don't forget that you can contribute a specific widget for a complex property item or a list item, using the item xpath.\n\n- The labels for each `diffBlock`, each widget and each subwidget in your `messages*.properties` files.\nFor example:\n\n```\nlabel.diffBlock.custom=My custom diff block title\nlabel.customSchema.customField=Custom field\nlabel.customSchema.customField.firstComplexItem=First item of the complex custom field\n```\n\n### Content diff\n\nWork in progress!\n\n# About Nuxeo\n\nNuxeo dramatically improves how content-based applications are built, managed and deployed, making customers more agile, innovative and successful. Nuxeo provides a next generation, enterprise ready platform for building traditional and cutting-edge content oriented applications. Combining a powerful application development environment with SaaS-based tools and a modular architecture, the Nuxeo Platform and Products provide clear business value to some of the most recognizable brands including Verizon, Electronic Arts, Sharp, FICO, the U.S. Navy, and Boeing. Nuxeo is headquartered in New York and Paris. More information is available at www.nuxeo.com.\n",
            "digest": "56f1f6c0b7c5c1f67502f8718bf655e4",
            "encoding": "UTF-8",
            "length": 16731,
            "mimeType": "text/plain",
            "name": "README.md"
          }
        ],
        "version": "2021.63"
      },
      "bundleId": "org.nuxeo.diff.content",
      "components": [
        {
          "@type": "NXComponent",
          "documentation": "\n    Adapters for content diff\n  \n",
          "documentationHtml": "<p>\nAdapters for content diff\n</p><p></p>",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.core.api.DocumentAdapterService--adapters",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapters/Contributions/org.nuxeo.ecm.diff.content.adapters--adapters",
              "id": "org.nuxeo.ecm.diff.content.adapters--adapters",
              "registrationOrder": 5,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.core.api.DocumentAdapterService",
                "name": "org.nuxeo.ecm.core.api.DocumentAdapterService",
                "type": "service"
              },
              "version": "2021.63.8",
              "xml": "<extension point=\"adapters\" target=\"org.nuxeo.ecm.core.api.DocumentAdapterService\">\n    <adapter class=\"org.nuxeo.ecm.diff.content.ContentDiffAdapter\" factory=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffDocumentModelAdapterFactory\"/>\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapters",
          "name": "org.nuxeo.ecm.diff.content.adapters",
          "requirements": [],
          "resolutionOrder": 174,
          "services": [],
          "startOrder": 190,
          "version": "2021.63.8",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.content.adapters\">\n  <documentation>\n    Adapters for content diff\n  </documentation>\n\n  <extension target=\"org.nuxeo.ecm.core.api.DocumentAdapterService\"\n    point=\"adapters\">\n    <adapter class=\"org.nuxeo.ecm.diff.content.ContentDiffAdapter\"\n      factory=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffDocumentModelAdapterFactory\" />\n  </extension>\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-document-adapter-contrib.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "componentClass": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
          "documentation": "\n    @author Antoine Taillefer (ataillefer@nuxeo.com)\n  \n",
          "documentationHtml": "<p></p>",
          "extensionPoints": [
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
              "descriptors": [
                "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterFactoryDescriptor"
              ],
              "documentation": "\n      @author Antoine Taillefer (ataillefer@nuxeo.com)\n    \n",
              "documentationHtml": "<p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent/ExtensionPoints/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--adapterFactory",
              "id": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--adapterFactory",
              "label": "adapterFactory (org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent)",
              "name": "adapterFactory",
              "version": "2021.63.8"
            },
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
              "descriptors": [
                "org.nuxeo.ecm.diff.content.adapter.MimeTypeContentDifferDescriptor"
              ],
              "documentation": "\n      Allows to contribute default implementation of\n      content diff according to the mime type.\n    \n",
              "documentationHtml": "<p>\nAllows to contribute default implementation of\ncontent diff according to the mime type.\n</p><p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent/ExtensionPoints/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--mimeTypeContentDiffer",
              "id": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--mimeTypeContentDiffer",
              "label": "mimeTypeContentDiffer (org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent)",
              "name": "mimeTypeContentDiffer",
              "version": "2021.63.8"
            },
            {
              "@type": "NXExtensionPoint",
              "componentId": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
              "descriptors": [
                "org.nuxeo.ecm.diff.content.MimeTypesDescriptor"
              ],
              "documentation": "\n      @since 10.10\n\n      Allows to contribute the list of blacklisted mime types for HTML\n      conversion.\n\n      By default, contributing a list merges its mime types\n      with the existing ones.\n      To remove a mime type, use enabled=false.\n      <code>\n    <extension point=\"htmlConversionBlacklistedMimeTypes\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n        <mimeTypes>\n            <mimeType>application/msword</mimeType>\n            <mimeType>application/rtf</mimeType>\n            <mimeType enabled=\"false\">application/pdf</mimeType>\n        </mimeTypes>\n    </extension>\n</code>\n\n\n      To override the whole list, use override=\"true\".\n      <code>\n    <extension point=\"htmlConversionBlacklistedMimeTypes\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n        <mimeTypes override=\"true\">\n            <mimeType>application/msword</mimeType>\n        </mimeTypes>\n    </extension>\n</code>\n",
              "documentationHtml": "<p>\n&#64;since 10.10\n</p><p>\nAllows to contribute the list of blacklisted mime types for HTML\nconversion.\n</p><p>\nBy default, contributing a list merges its mime types\nwith the existing ones.\nTo remove a mime type, use enabled&#61;false.\n</p><p></p><pre><code>    &lt;extension point&#61;&#34;htmlConversionBlacklistedMimeTypes&#34; target&#61;&#34;org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent&#34;&gt;\n        &lt;mimeTypes&gt;\n            &lt;mimeType&gt;application/msword&lt;/mimeType&gt;\n            &lt;mimeType&gt;application/rtf&lt;/mimeType&gt;\n            &lt;mimeType enabled&#61;&#34;false&#34;&gt;application/pdf&lt;/mimeType&gt;\n        &lt;/mimeTypes&gt;\n    &lt;/extension&gt;\n</code></pre><p>\nTo override the whole list, use override&#61;&#34;true&#34;.\n</p><p></p><pre><code>    &lt;extension point&#61;&#34;htmlConversionBlacklistedMimeTypes&#34; target&#61;&#34;org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent&#34;&gt;\n        &lt;mimeTypes override&#61;&#34;true&#34;&gt;\n            &lt;mimeType&gt;application/msword&lt;/mimeType&gt;\n        &lt;/mimeTypes&gt;\n    &lt;/extension&gt;\n</code></pre><p></p>",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent/ExtensionPoints/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--htmlConversionBlacklistedMimeTypes",
              "id": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--htmlConversionBlacklistedMimeTypes",
              "label": "htmlConversionBlacklistedMimeTypes (org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent)",
              "name": "htmlConversionBlacklistedMimeTypes",
              "version": "2021.63.8"
            }
          ],
          "extensions": [],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
          "name": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
          "requirements": [],
          "resolutionOrder": 175,
          "services": [
            {
              "@type": "NXService",
              "componentId": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent/Services/org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManager",
              "id": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManager",
              "overriden": false,
              "version": "2021.63.8"
            }
          ],
          "startOrder": 842,
          "version": "2021.63.8",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component\n  name=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n  <implementation\n    class=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\" />\n\n  <documentation>\n    @author Antoine Taillefer (ataillefer@nuxeo.com)\n  </documentation>\n\n  <service>\n    <provide\n      interface=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManager\" />\n  </service>\n\n  <extension-point name=\"adapterFactory\">\n    <documentation>\n      @author Antoine Taillefer (ataillefer@nuxeo.com)\n    </documentation>\n    <object\n      class=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterFactoryDescriptor\" />\n  </extension-point>\n\n  <extension-point name=\"mimeTypeContentDiffer\">\n    <documentation>\n      Allows to contribute default implementation of\n      content diff according to the mime type.\n    </documentation>\n    <object\n      class=\"org.nuxeo.ecm.diff.content.adapter.MimeTypeContentDifferDescriptor\" />\n  </extension-point>\n\n  <extension-point\n    name=\"htmlConversionBlacklistedMimeTypes\">\n    <documentation>\n      @since 10.10\n\n      Allows to contribute the list of blacklisted mime types for HTML\n      conversion.\n\n      By default, contributing a list merges its mime types\n      with the existing ones.\n      To remove a mime type, use enabled=false.\n      <code>\n        <extension\n          target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n          point=\"htmlConversionBlacklistedMimeTypes\">\n          <mimeTypes>\n            <mimeType>application/msword</mimeType>\n            <mimeType>application/rtf</mimeType>\n            <mimeType enabled=\"false\">application/pdf</mimeType>\n          </mimeTypes>\n        </extension>\n      </code>\n\n      To override the whole list, use override=\"true\".\n      <code>\n        <extension\n          target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n          point=\"htmlConversionBlacklistedMimeTypes\">\n          <mimeTypes override=\"true\">\n            <mimeType>application/msword</mimeType>\n          </mimeTypes>\n        </extension>\n      </code>\n    </documentation>\n    <object\n      class=\"org.nuxeo.ecm.diff.content.MimeTypesDescriptor\" />\n  </extension-point>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-adapter-framework.xml",
          "xmlPureComponent": false
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentation": "\n      Default builtin content diff adapters\n    \n",
              "documentationHtml": "<p>\nDefault builtin content diff adapters\n</p><p></p>",
              "extensionPoint": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--adapterFactory",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.contrib/Contributions/org.nuxeo.ecm.diff.content.adapter.contrib--adapterFactory",
              "id": "org.nuxeo.ecm.diff.content.adapter.contrib--adapterFactory",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "name": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "type": "service"
              },
              "version": "2021.63.8",
              "xml": "<extension point=\"adapterFactory\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n\n    <documentation>\n      Default builtin content diff adapters\n    </documentation>\n\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--mimeTypeContentDiffer",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.contrib/Contributions/org.nuxeo.ecm.diff.content.adapter.contrib--mimeTypeContentDiffer",
              "id": "org.nuxeo.ecm.diff.content.adapter.contrib--mimeTypeContentDiffer",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "name": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "type": "service"
              },
              "version": "2021.63.8",
              "xml": "<extension point=\"mimeTypeContentDiffer\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n    <contentDiffer class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/html</pattern>\n    </contentDiffer>\n    <contentDiffer class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/plain</pattern>\n    </contentDiffer>\n    <contentDiffer class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/xml</pattern>\n    </contentDiffer>\n    <contentDiffer class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>application/json</pattern>\n    </contentDiffer>\n  </extension>"
            },
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent--htmlConversionBlacklistedMimeTypes",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.contrib/Contributions/org.nuxeo.ecm.diff.content.adapter.contrib--htmlConversionBlacklistedMimeTypes",
              "id": "org.nuxeo.ecm.diff.content.adapter.contrib--htmlConversionBlacklistedMimeTypes",
              "registrationOrder": 0,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "name": "org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent",
                "type": "service"
              },
              "version": "2021.63.8",
              "xml": "<extension point=\"htmlConversionBlacklistedMimeTypes\" target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\">\n    <mimeTypes>\n      <!-- PDF -->\n      <mimeType>application/pdf</mimeType>\n\n      <!-- Office spreadsheet -->\n      <mimeType>application/vnd.ms-excel</mimeType>\n      <mimeType>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\n      </mimeType>\n      <mimeType>application/vnd.sun.xml.calc</mimeType>\n      <mimeType>application/vnd.sun.xml.calc.template</mimeType>\n      <mimeType>application/vnd.oasis.opendocument.spreadsheet\n      </mimeType>\n      <mimeType>application/vnd.oasis.opendocument.spreadsheet-template\n      </mimeType>\n\n      <!-- Office presentation -->\n      <mimeType>application/vnd.ms-powerpoint</mimeType>\n      <mimeType>application/vnd.openxmlformats-officedocument.presentationml.presentation\n      </mimeType>\n      <mimeType>application/vnd.sun.xml.impress</mimeType>\n      <mimeType>application/vnd.sun.xml.impress.template</mimeType>\n      <mimeType>application/vnd.oasis.opendocument.presentation\n      </mimeType>\n      <mimeType>application/vnd.oasis.opendocument.presentation-template\n      </mimeType>\n    </mimeTypes>\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.adapter.contrib",
          "name": "org.nuxeo.ecm.diff.content.adapter.contrib",
          "requirements": [],
          "resolutionOrder": 176,
          "services": [],
          "startOrder": 189,
          "version": "2021.63.8",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.content.adapter.contrib\">\n  <extension\n    target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n    point=\"adapterFactory\">\n\n    <documentation>\n      Default builtin content diff adapters\n    </documentation>\n\n  </extension>\n\n  <extension\n    target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n    point=\"mimeTypeContentDiffer\">\n    <contentDiffer\n      class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/html</pattern>\n    </contentDiffer>\n    <contentDiffer\n      class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/plain</pattern>\n    </contentDiffer>\n    <contentDiffer\n      class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>text/xml</pattern>\n    </contentDiffer>\n    <contentDiffer\n      class=\"org.nuxeo.ecm.diff.content.adapter.HtmlContentDiffer\">\n      <pattern>application/json</pattern>\n    </contentDiffer>\n  </extension>\n\n  <extension\n    target=\"org.nuxeo.ecm.diff.content.adapter.ContentDiffAdapterManagerComponent\"\n    point=\"htmlConversionBlacklistedMimeTypes\">\n    <mimeTypes>\n      <!-- PDF -->\n      <mimeType>application/pdf</mimeType>\n\n      <!-- Office spreadsheet -->\n      <mimeType>application/vnd.ms-excel</mimeType>\n      <mimeType>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\n      </mimeType>\n      <mimeType>application/vnd.sun.xml.calc</mimeType>\n      <mimeType>application/vnd.sun.xml.calc.template</mimeType>\n      <mimeType>application/vnd.oasis.opendocument.spreadsheet\n      </mimeType>\n      <mimeType>application/vnd.oasis.opendocument.spreadsheet-template\n      </mimeType>\n\n      <!-- Office presentation -->\n      <mimeType>application/vnd.ms-powerpoint</mimeType>\n      <mimeType>application/vnd.openxmlformats-officedocument.presentationml.presentation\n      </mimeType>\n      <mimeType>application/vnd.sun.xml.impress</mimeType>\n      <mimeType>application/vnd.sun.xml.impress.template</mimeType>\n      <mimeType>application/vnd.oasis.opendocument.presentation\n      </mimeType>\n      <mimeType>application/vnd.oasis.opendocument.presentation-template\n      </mimeType>\n    </mimeTypes>\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-adapter-contrib.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentation": "\n      Allows to limit the diff count between two files.\n      @since 2021.24\n    \n",
              "documentationHtml": "<p>\nAllows to limit the diff count between two files.\n&#64;since 2021.24\n</p><p></p>",
              "extensionPoint": "org.nuxeo.runtime.ConfigurationService--configuration",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.settings/Contributions/org.nuxeo.ecm.diff.settings--configuration",
              "id": "org.nuxeo.ecm.diff.settings--configuration",
              "registrationOrder": 25,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.runtime.ConfigurationService",
                "name": "org.nuxeo.runtime.ConfigurationService",
                "type": "service"
              },
              "version": "2021.63.8",
              "xml": "<extension point=\"configuration\" target=\"org.nuxeo.runtime.ConfigurationService\">\n    <documentation>\n      Allows to limit the diff count between two files.\n      @since 2021.24\n    </documentation>\n    <property name=\"nuxeo.diff.limit\">100000</property>\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.settings",
          "name": "org.nuxeo.ecm.diff.settings",
          "requirements": [],
          "resolutionOrder": 177,
          "services": [],
          "startOrder": 195,
          "version": "2021.63.8",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.settings\">\n  <extension target=\"org.nuxeo.runtime.ConfigurationService\" point=\"configuration\">\n    <documentation>\n      Allows to limit the diff count between two files.\n      @since 2021.24\n    </documentation>\n    <property name=\"nuxeo.diff.limit\">${nuxeo.diff.limit:=100000}</property>\n  </extension>\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-config.xml",
          "xmlPureComponent": true
        },
        {
          "@type": "NXComponent",
          "documentationHtml": "",
          "extensionPoints": [],
          "extensions": [
            {
              "@type": "NXContribution",
              "documentationHtml": "",
              "extensionPoint": "org.nuxeo.ecm.core.convert.service.ConversionServiceImpl--converter",
              "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.converter.contrib/Contributions/org.nuxeo.ecm.diff.content.converter.contrib--converter",
              "id": "org.nuxeo.ecm.diff.content.converter.contrib--converter",
              "registrationOrder": 5,
              "targetComponentName": {
                "rawName": "service:org.nuxeo.ecm.core.convert.service.ConversionServiceImpl",
                "name": "org.nuxeo.ecm.core.convert.service.ConversionServiceImpl",
                "type": "service"
              },
              "version": "2021.63.8",
              "xml": "<extension point=\"converter\" target=\"org.nuxeo.ecm.core.convert.service.ConversionServiceImpl\">\n\n    <converter class=\"org.nuxeo.ecm.diff.content.converters.ContentDiffHtmlConverter\" name=\"contentDiffHtmlConverter\">\n      <sourceMimeType>*</sourceMimeType>\n      <destinationMimeType>text/html</destinationMimeType>\n    </converter>\n\n    <converter class=\"org.nuxeo.ecm.diff.content.converters.ContentDiffTextConverter\" name=\"contentDiffTextConverter\">\n      <sourceMimeType>*</sourceMimeType>\n      <destinationMimeType>text/plain</destinationMimeType>\n    </converter>\n\n  </extension>"
            }
          ],
          "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content/org.nuxeo.ecm.diff.content.converter.contrib",
          "name": "org.nuxeo.ecm.diff.content.converter.contrib",
          "requirements": [
            "org.nuxeo.ecm.core.convert.plugins",
            "org.nuxeo.ecm.platform.convert.plugins"
          ],
          "resolutionOrder": 340,
          "services": [],
          "startOrder": 191,
          "version": "2021.63.8",
          "xmlFileContent": "<?xml version=\"1.0\"?>\n<component name=\"org.nuxeo.ecm.diff.content.converter.contrib\">\n\n  <require>org.nuxeo.ecm.platform.convert.plugins</require>\n  <require>org.nuxeo.ecm.core.convert.plugins</require>\n\n  <extension target=\"org.nuxeo.ecm.core.convert.service.ConversionServiceImpl\"\n    point=\"converter\">\n\n    <converter name=\"contentDiffHtmlConverter\" class=\"org.nuxeo.ecm.diff.content.converters.ContentDiffHtmlConverter\">\n      <sourceMimeType>*</sourceMimeType>\n      <destinationMimeType>text/html</destinationMimeType>\n    </converter>\n\n    <converter name=\"contentDiffTextConverter\" class=\"org.nuxeo.ecm.diff.content.converters.ContentDiffTextConverter\">\n      <sourceMimeType>*</sourceMimeType>\n      <destinationMimeType>text/plain</destinationMimeType>\n    </converter>\n\n  </extension>\n\n</component>\n",
          "xmlFileName": "/OSGI-INF/content-diff-convert-service-contrib.xml",
          "xmlPureComponent": true
        }
      ],
      "fileName": "nuxeo-diff-content-2021.63.8.jar",
      "groupId": "org.nuxeo.ecm",
      "hierarchyPath": "/grp:org.nuxeo.ecm/grp:org.nuxeo.diff/org.nuxeo.diff.content",
      "id": "org.nuxeo.diff.content",
      "location": "",
      "manifest": "Manifest-Version: 1.0\r\nArchiver-Version: Plexus Archiver\r\nCreated-By: Apache Maven\r\nBuilt-By: root\r\nBuild-Jdk: 11.0.24\r\nBundle-ManifestVersion: 2\r\nBundle-Version: 5.6\r\nBundle-ActivationPolicy: lazy\r\nBundle-ClassPath: .\r\nBundle-Name: org.nuxeo.diff\r\nBundle-RequiredExecutionEnvironment: JavaSE-1.6\r\nBundle-Vendor: Nuxeo\r\nBundle-SymbolicName: org.nuxeo.diff.content;singleton:=true\r\nNuxeo-Component: OSGI-INF/content-diff-document-adapter-contrib.xml,OS\r\n GI-INF/content-diff-adapter-framework.xml,OSGI-INF/content-diff-adapt\r\n er-contrib.xml,OSGI-INF/content-diff-convert-service-contrib.xml,OSGI\r\n -INF/content-diff-config.xml\r\n\r\n",
      "maxResolutionOrder": 340,
      "minResolutionOrder": 174,
      "packages": [
        "nuxeo-diff"
      ],
      "parentReadme": {
        "blobProviderId": "default",
        "content": "# Nuxeo Diff\n\nThis repo hosts the source code of a plugin for Nuxeo Platform that allows to render a diff between two documents or two versions of a document.\nThe comparison takes into account all the properties shared by the documents, which means that if a comparison is done between two documents of a different type, only the schemas in common will be \"diffed\".\nThe comparison also takes into account blob-type properties.\n\n\n## Building and deploying\n\n    mvn clean install\n\n## Deploying\n\nInstall [the Nuxeo Diff Marketplace Package](https://connect.nuxeo.com/nuxeo/site/marketplace/package/nuxeo-diff).\n\n## Configuring\n\n### Diff display\n\nThe `DiffDisplayService` offers several extension points to configure the document diff display.\nMost of the code samples exposed here can be found in the [diff-display-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-display-contrib.xml) and [diff-widgets-contrib.xml](nuxeo-diff-jsf/src/main/resources/OSGI-INF/diff-widgets-contrib.xml) files.\n\n#### Configuring groups of properties to display with the diffDisplay extension point.\n\nA `diffDisplay` contribution represents a number of `diffBlocks` that you want to display when asking for a document comparison.\nIt is bound to a document type.\nA `diffBlock` contribution represents a number of properties (fields) that you want to display (see next section).\n\nWhen asking for the comparison between 2 versions of a document, the `diffDisplay` bound to the document type or a super type is used.\nIf no `diffDisplay` is found for this type or a super type a fall back is done on the default diff display mode: one block per document schema and for each block all the fields of the schema that are different.\n\n*Beware that in this case the order of the schemas and of the fields is undefined.*\n\nWhen asking for the comparison between 2 documents:\n- If they are of the same type: if  a `diffDisplay` is found for this type or a super type then it is used, else a fall back is done on the default diff display mode.\n- If they are of different types: if  a `diffDisplay` is found for a common super type then it is used, else a fall back is done on the default diff display mode.\n\nFor example, this is the `diffDisplay` contribution bound to the _File_ type:\n```xml\n<diffDisplay type=\"File\">\n  <diffBlocks>\n    <diffBlock name=\"heading\" />\n    <diffBlock name=\"dublincore\" />\n    <diffBlock name=\"files\" />\n  </diffDisplay>\n</diffBlocks>\n```\n\n_Note that the order of the diffBlocks is taken into account when rendering the diff display._\n\n#### Configuring a group of properties to display with the diffBlock extension point\n\nA `diffBlock` contribution represents a number of `fields` that you want to display. It is rendered as a foldable box.\nThe `label` attribute of a `diffBlock` contribution is used as the title of the foldable box.\nA `field` is defined by its `schema` and its `name`.\n\nFor example, this is the \"heading\" `diffBlock` contribution:\n```xml\n<diffBlock name=\"heading\" label=\"label.diffBlock.heading\">\n  <fields>\n    <field schema=\"dublincore\" name=\"title\" />\n    <field schema=\"dublincore\" name=\"description\" />\n  </fields>\n</diffBlock>\n```\n_Note that the order of the fields is taken into account when rendering the diff block._\n\nFor complex properties, you can contribute inside the `field` element the property `items` that you want to display:\n```xml\n<field schema=\"complextypes\" name=\"complex\">\n  <items>\n    <item name=\"stringItem\" />\n    <item name=\"thirdItem\" />\n    <item name=\"fourthItem\" />\n  </items>\n</field>\n```\n\n_Note that the order of the items is taken into account when rendering the field._\n\nThis is used for the `files` field of the `files` diff block:\n```xml\n<field schema=\"files\" name=\"files\">\n  <items>\n    <!-- Display the file only, not the filename which is managed\n         by the file widget type -->\n    <item name=\"file\" displayContentDiffLinks=\"true\" />\n  </items>\n</field>\n```\n\nIf no `items` are specified, all the property items are displayed.\n\nFor content properties (that hold a blob) or string ones you can set the `displayContentDiffLinks` attribute to `true` on a `field` or an `item` to display the content diff links.\nThese links will open a fancybox showing the detailed content diff using the usual green and red colors to distinguish the added/removed parts of the content.\nFor now, 2 links are displayed: _Textual diff_ based on a text conversion and _Html diff_ based on an html conversion (keeps the content layout).\n\n#### Configuring property widgets with the widgets extension point\n\n##### Principle\n\nWhen rendering a `diffBlock`, the `DiffDisplayService` builds a layout definition on the fly, including a layout row for each `field` of the `diffBlock`.\nEach row contains a widget definition for the `field`, and the layout template renders 2 instances of this widget definition: one for the left document and one for the right document.\nThe content diff links, if displayed, are also rendered by a widget inside the layout row.\n\nHow is the widget definition built for a given `field`?\nA lookup is done in the `LayoutStore` service to find a specific widget definition named with the xpath of the property.\nIf such a definition is not found, a lookup is done to find a generic widget definition named with the type of the property.\n\nThis allows you to only contribute a specific widget definition if the generic one doesn't match your needs for a given field, typically if you need a custom template, label or custom properties.\n\n##### Example\n\nLets say we have contributed the following `diffBlock`:\n```xml\n<diffBlock name=\"myCustomBlock\" label=\"label.diffBlock.custom\">\n  <fields>\n    <field schema=\"file\" name=\"content\" />\n    <field schema=\"dublincore\" name=\"title\" />\n  </fields>\n</diffBlock>\n```\n\nand the following widgets to the `widgets` extension point of the `org.nuxeo.ecm.platform.forms.layout.LayoutStore` component:\n```xml\n<extension target=\"org.nuxeo.ecm.platform.forms.layout.LayoutStore\"\n  point=\"widgets\">\n\n  <widget name=\"file:content\" type=\"file\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <labels>\n      <label mode=\"any\">label.summary.download.file</label>\n    </labels>\n    <translated>true</translated>\n    <properties mode=\"any\">\n    </properties>\n  </widget>\n\n  <widget name=\"string\" type=\"template\">\n    <categories>\n      <category>diff</category>\n    </categories>\n    <properties mode=\"any\">\n      <property name=\"widgetType\">text</property>\n      <property name=\"template\">\n        /widgets/generic_diff_widget_template.xhtml\n      </property>\n    </properties>\n  </widget>\n\n</extension>\n```\n\nWhen rendering the \"myCustomBlock\" `diffBlock`, the `DiffDisplayService` will:\n\n- Look for a specific widget definition named \"file:content\" in the `LayoutStore`, find it and use it for the \"file:content\" field.\n\n- Look for a specific widget definition named \"dublincore:title\" in the `LayoutStore`, won't find it and therefore will look for a generic widget definition named with the field type, ie. \"string\", find it and use it for the dublincore:title field.\n\nIn this use case, the \"string\" generic widget definition is sufficient to display the \"dublincore:title\" field.\nIt uses a widget of type \"text\" with \"label.dublincore.title\" as a label and \"dublincore:title\" as a field definition.\nWe can easily understand here the interest of generic widgets: once you have the type and xpath of a property, the matching widget definition can be computed on the fly using the property type to guess the widget type (\"string\" => \"text\", \"date\" => \"datetime\", etc.) and the property xpath for the field definition and label.\n\nThe \"file:content\" specific widget definition is contributed here to use a custom label \"label.summary.download.file\" instead of the one that would have been generated for the \"content\" generic widget definition: \"label.file.content\".\n\n_Note that in both cases (generic and specific) you don't need to define the widget field definitions since they are automatically computed from the property xpath, except in particular cases like \"note:note\" where the \"mime-type\" field is needed._\n\n##### List and complex properties\n\nYou might already know that the widgets used to display list and complex properties have subwidgets.\nIn the case of a list property, a subwidget is needed for the list items; in the case of a complex property, a subwidget is needed for each item of the complex property.\nThe lookup done by the `DiffDisplayService_` for the first-level widgets is also done recursively for the subwidgets!\n\n###### List property\n\nFor a list property, lets take the example of \"dublincore:contributors\", which is a string list.\n\n- To display the list, nothing special is needed so the \"scalarList\" generic widget definition can be used.\n\n- To display a list item (a contributor, which is of type \"string\"), the \"string\" generic widget definition doesn't match our needs: it would display the contributor's username whereas we want to display its fullname (firstname lastname).\nSo we need a specific widget definition for the list items subwidget to use a custom template able to display the contributor's fullname.\nThe name of this widget definition must match the xpath of the list item property, ie. \"dublincore:contributors/item\".\n\nTherefore, two widget definitions are involved:\n\n- The \"scalarList\" generic widget definition:\n\n```xml\n<widget name=\"scalarList\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"displayAllItems\">false</property>\n    <property name=\"displayItemIndexes\">true</property>\n    <property name=\"template\">\n      /widgets/list_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"dublincore:contributors/item\" specific widget definition:\n\n```xml\n<widget name=\"dublincore:contributors/item\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.dublincore.contributors.item</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"template\">/widgets/contributors_item_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n###### Complex property\n\nFor a complex property, lets take the example of a \"complextypes:complex\" property with two items \"stringItem\" and \"directoryItem\".\n\"stringItem\" is a simple string, but \"directoryItem\" is a string that needs to be bound to the \"myDirectory\" directory.\n\n- To display the complex property, nothing special is needed so the \"complex\" generic widget definition can be used.\n\n- To display the \"directoryItem\" item, the \"string\" generic widget definition doesn't match our needs: it would display the directory entry code stored in the backend whereas we want to display its label.\nSo we need a specific widget definition for the \"directoryItem\" subwidget to use the \"selectOneDirectory\" widget type bound to the \"myDirectory\" directory.\nAs for a list item, the name of this widget definition must match the xpath of the complex property item, ie. \"complextypes:complex/directoryItem\".\n\nTherefore, two widget definitions are involved:\n\n- The \"complex\" generic widget definition:\n\n```xml\n<widget name=\"complex\" type=\"template\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <properties mode=\"any\">\n    <property name=\"display\">inline</property>\n    <property name=\"template\">\n      /widgets/complex_diff_widget_template.xhtml\n    </property>\n  </properties>\n</widget>\n```\n\n- The \"complextypes:complex/directoryItem\" specific widget definition:\n\n```xml\n<widget name=\"complextypes:complex/directoryItem\" type=\"selectOneDirectory\">\n  <categories>\n    <category>diff</category>\n  </categories>\n  <labels>\n    <label mode=\"any\">label.complextypes.complex.directoryItem</label>\n  </labels>\n  <translated>true</translated>\n  <properties mode=\"any\">\n    <property name=\"directoryName\">myDirectory</property>\n    <property name=\"localize\">true</property>\n    <property name=\"ordering\">ordering,label</property>\n  </properties>\n</widget>\n```\n\n###### Useful widget properties\n\nYou can use the following properties on a list widget definition (typically \"scalarList\", \"complexList\" or \"files:files\"):\n\n`<property name=\"displayAllItems\">[true|false]</property>`\nIf set to `true`, all the list items will be displayed, otherwise only the different ones will be.\n\n`<property name=\"displayItemIndexes\">[true|false]</property>`\nIf set to `true`, a subwidget will be added to the widget definition to display the list item indexes.\n\nYou can use the following property on a complex widget definition (typically \"complex\"):\n\n`<property name=\"display\">[inline|*]</property>`\nIf set to `inline` the complex items will be displayed as a table with one line and one column per item, otherwise as a table with one column and one line per item.\n\n##### About the value bound to the diff widgets\n\nIf you take a look at [layout_diff_template.xhtml](nuxeo-diff-jsf/src/main/resources/web/nuxeo.war/layouts/layout_diff_template.xhtml), you will see that the `value` passed to the `<nxl:widget>` tag is `#{value.leftValue}` or `#{value.rightValue}`, `value` being the object passed to the `<nxl:layout>` tag `value` attribute: `diffDisplayBlock`, of type `DiffDisplayBlockImpl`.\nThe `leftValue` and `rightValue` members of `DiffDisplayBlockImpl` are of type `Map<String, Map<String, PropertyDiffDisplay>>`. The first level Map keys are schema names, the second level ones are field keys.\nFinally, the `PropertyDiffDisplay` object has two members: `value` and `styleClass`, `value` holding the value to display and `styleClass` the css style class to apply to the &lt;span&gt; wrapping the value.\n\nFor example if we compare two documents where only the \"dublincore:title\" property is different (\"My first doc\" and \"My second doc\") we could have the following `diffDisplayBlock` object:\n\n```java\ndiffDisplayBlock.getLeftValue() = {dublincore={title={value=\"My first doc\", styleClass=\"redBackgroundColor\"}}}\ndiffDisplayBlock.getRightValue() = {dublincore={title={value=\"My second doc\", styleClass=\"greenBackgroundColor\"}}}\n```\n\nOn the widget side, the field definitions must match the `diffDisplayBlock` object structure, that's why the generated field definitions of the widget used for \"dublincore:title\" would be:\n\n```xml\n<fields>\n  <field>dublincore:title/value</field>\n  <field>dublincore:title/styleClass</field>\n</fields>\n```\n\nThis is important to know when designing a custom template for a diff widget (ie. where field definitions are automatically generated): you can use `#{field_0}` for the value itself and `#{field_1`} for the css style class associated to the value.\nBy default, only the items of a complex property or of a list property where the `displayAllItems` widget property is `true` can have a styleClass equal to `redBackgroundColor` or `greenBackgroundColor` in order to highlight the different items among all.\n\n#### To summarize: what you need to contribute to have a nice diff result for your custom document types\n\n- A `diffDisplay` contribution for each document type.\n\n- The associated `diffBlock` contributions. Don't forget that you can specify the items you want to display for a complex property and the fields/items for which you want to display the content diff links.\n\n- The specific widgets needed when the generic ones don't match your needs. Typically for a date property if you need to change the date format, or for a property bound to a directory to specifiy the directory name. Also don't forget that you can contribute a specific widget for a complex property item or a list item, using the item xpath.\n\n- The labels for each `diffBlock`, each widget and each subwidget in your `messages*.properties` files.\nFor example:\n\n```\nlabel.diffBlock.custom=My custom diff block title\nlabel.customSchema.customField=Custom field\nlabel.customSchema.customField.firstComplexItem=First item of the complex custom field\n```\n\n### Content diff\n\nWork in progress!\n\n# About Nuxeo\n\nNuxeo dramatically improves how content-based applications are built, managed and deployed, making customers more agile, innovative and successful. Nuxeo provides a next generation, enterprise ready platform for building traditional and cutting-edge content oriented applications. Combining a powerful application development environment with SaaS-based tools and a modular architecture, the Nuxeo Platform and Products provide clear business value to some of the most recognizable brands including Verizon, Electronic Arts, Sharp, FICO, the U.S. Navy, and Boeing. Nuxeo is headquartered in New York and Paris. More information is available at www.nuxeo.com.\n",
        "digest": "56f1f6c0b7c5c1f67502f8718bf655e4",
        "encoding": "UTF-8",
        "length": 16731,
        "mimeType": "text/plain",
        "name": "README.md"
      },
      "requirements": [],
      "version": "2021.63.8"
    }
  ],
  "creationDate": 1732721792848,
  "key": "Nuxeo Platform-2021.63",
  "name": "Nuxeo Platform",
  "operations": [],
  "packages": [
    {
      "@type": "NXPackage",
      "bundles": [
        "org.nuxeo.diff.content",
        "org.nuxeo.diff.core",
        "org.nuxeo.diff.jsf"
      ],
      "conflicts": [],
      "dependencies": [
        "nuxeo-jsf-ui"
      ],
      "hierarchyPath": "/nuxeo-diff-2021.63.8",
      "id": "nuxeo-diff-2021.63.8",
      "name": "nuxeo-diff",
      "optionalDependencies": [],
      "packageType": "addon",
      "title": "Nuxeo Diff",
      "version": "2021.63.8"
    }
  ],
  "pluginSnapshots": {},
  "releaseDate": 1732721792848,
  "version": "2021.63"
}